﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace DotNetRepository
{
    public static class Repository<TEntity> 
        where TEntity : class, IEntity
    {
        private static readonly IEntityRepository<TEntity> repository;

        static Repository()
        {
            if (Settings.Default.DefaultRepository == "LinqToSql")
            {
                repository = LinqToSql.LinqToSqlRepository<TEntity>.Instance;
            }
            else
            {
                repository = LinqToObjects.LinqToObjectsRepository<TEntity>.Instance;
            }
        }

        public static IEntityRepository<TEntity> Instance
        {
            get { return repository; }
        }

        public static TEntity GetByID(Guid id)
        {
            return repository.GetByID(id);
        }

        public static TEntity GetCachedByID(Guid id)
        {
            return repository.GetCachedByID(id);
        }

        public static bool IsDirty(TEntity entity)
        {
            return repository.IsDirty(entity);
        }

        public static void Save(TEntity entity, object sender)
        {
            repository.Save(entity, sender);
        }

        public static void Save(TEntity entity)
        {
            Save(entity, null);
        }

        public static void Revert(TEntity entity)
        {
            repository.Revert(entity);
        }

        public static void Delete(TEntity entity, object sender)
        {
            repository.Delete(entity, sender);
        }

        public static void Delete(TEntity entity)
        {
            Delete(entity, null);
        }

        public static bool IsCached(Guid id)
        {
            return repository.IsCached(id);
        }

        public static bool Contains(TEntity entity)
        {
            return repository.Contains(entity);
        }

        public static bool Contains(Guid id)
        {
            return repository.Contains(id);
        }

        public static bool Any(Expression<Func<TEntity, bool>> predicate)
        {
            return repository.Any(predicate);
        }

        public static List<TEntity> Where(Expression<Func<TEntity, bool>> predicate)
        {
            return repository.Where(predicate);
        }

        public static List<TEntity> GetByIDs(IEnumerable<Guid> ids)
        {
            return repository.GetByIDs(ids);
        }

        public static List<Guid> GetIDs(Expression<Func<TEntity, bool>> predicate)
        {
            return repository.GetIDs(predicate);
        }

        public static TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate)
        {
            return repository.FirstOrDefault(predicate);
        }

        public static TEntity LastOrDefault(Expression<Func<TEntity, bool>> predicate)
        {
            return repository.LastOrDefault(predicate);
        }

        public static IEnumerable<TEntity> GetTable(ref object context)
        {
            return repository.GetTable(ref context);
        }
    }

    public static class Repository
    {
        public static void Save(IEntity entity, object sender)
        {
            if (entity == null) return;
            
            typeof (Repository<>)
                .MakeGenericType(new[] {entity.GetType()})
                .GetMethod("Save", new[] { entity.GetType(), typeof(object) })
                .Invoke(null, new[] { entity, sender });
        }

        public static void Delete(IEntity entity, object sender)
        {
            if (entity == null) return;
            typeof(Repository<>)
                .MakeGenericType(new[] { entity.GetType() })
                .GetMethod("Delete", new[] { entity.GetType(), typeof(object) })
                .Invoke(null, new[] { entity, sender });
        }
    }
}
